package com.sl.biz.modular.process.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.sl.biz.modular.group.dao.enums.GroupRelationTypeCodeEnum;
import com.sl.biz.modular.group.service.SquareLakeGroupBizService;
import com.sl.biz.modular.group.service.impl.SquareLakeGroupBizServiceImpl;
import com.sl.biz.modular.process.controller.request.ProcessCompGetByIdRequest;
import com.sl.biz.modular.process.dao.domain.dto.ProcessCompDTO;
import com.sl.biz.modular.process.dao.domain.entity.ProcessCompDO;
import com.sl.biz.modular.process.dao.service.ProcessCompDaoService;
import com.sl.biz.modular.process.dao.service.ProcessCompVersionBuildDaoService;
import com.sl.biz.modular.process.dao.service.ProcessCompVersionDaoService;
import com.sl.biz.modular.process.service.ProcessCompBizService;
import com.sl.core.domain.dto.ProcessComponentDTO;
import com.sl.core.engine.plugin.ProcessPluginRegistry;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;


@Service
@RequiredArgsConstructor
public class ProcessCompBizServiceImpl implements ProcessCompBizService {

    private final ProcessCompDaoService compDaoService;
    private final ProcessCompVersionDaoService versionDaoService;
    private final ProcessCompVersionBuildDaoService buildDaoService;

    private final SquareLakeGroupBizService groupBizService;

    @Override
    public List<ProcessCompDTO> list(ProcessCompDO processComp) {
        String groupCode = processComp.getGroupCode();
        List<ProcessCompDTO> list = compDaoService.queryList(processComp);
        if (ObjectUtil.isNull(list)) {
            list = Lists.newArrayList();
        }
        list.forEach(v -> v.setSystemFlag(false));
        //还要查询出系统的
        List<ProcessComponentDTO> listed = ProcessPluginRegistry.INSTANCE.list();

        List<ProcessCompDTO> collect = listed.stream().filter(v -> {

            return BooleanUtil.isTrue(v.getSystemFlag());
        }).filter(v -> {
            String gc = v.getGroupCode();
            if (StrUtil.isBlank(groupCode)) {
                return true;
            }
            return StrUtil.equals(gc, groupCode);
        }).map(v -> {
            ProcessCompDTO processCompDTO = new ProcessCompDTO();
            processCompDTO.setId(v.getPluginCode());
            processCompDTO.setCompName(v.getName());
            processCompDTO.setCompCode(v.getPluginCode());
            processCompDTO.setGroupCode(v.getGroupCode());
            processCompDTO.setGroupName(v.getGroupName());
            processCompDTO.setIcon(v.getIcon());
            processCompDTO.setSystemFlag(v.getSystemFlag());
            return processCompDTO;
        }).toList();
        list.addAll(collect);
        return list;
    }

    @Override
    public Boolean save(ProcessCompDO processComp) {
        String id = processComp.getId();
        if (StrUtil.isNotBlank(id)) {
            return compDaoService.updateById(processComp);
        }
        return compDaoService.add(processComp);
    }


    @Override
    public ProcessCompDTO getById(ProcessCompGetByIdRequest addRequest) {
        String id = addRequest.getId();
        Boolean systemFlag = addRequest.getSystemFlag();
        if (BooleanUtil.isTrue(systemFlag)) {
            ProcessCompDO processCompDO = new ProcessCompDO();
            List<ProcessCompDTO> list = this.list(processCompDO);
            if (CollUtil.isEmpty(list)) {
                return null;
            }
            ProcessCompDTO processCompDTO = list.stream().filter(v -> v.getId().equals(id)).findFirst().orElse(null);
            return processCompDTO;
        }
        ProcessCompDO byId = compDaoService.getById(id);

        return BeanUtil.copyProperties(byId, ProcessCompDTO.class);
    }

    @Override
    public Boolean removeById(ProcessCompDO processComp) {
        ProcessCompDO byId = compDaoService.getById(processComp.getId());

        //先删除版本
        versionDaoService.removeByCompCode(byId.getCompCode());

        buildDaoService.removeByCompCode(byId.getCompCode());

        return compDaoService.removeById(processComp.getId());
    }

    @Override
    public List<Tree<String>> groupTree() {
        List<Tree<String>> tree = groupBizService.tree(GroupRelationTypeCodeEnum.COMP.getCode(), null);
        if (CollUtil.isEmpty(tree)) {
            tree = Lists.newArrayList();
        }
        List<ProcessCompDTO> list = this.list(new ProcessCompDO());

        if (CollUtil.isEmpty(list)) {
            return tree;
        }
        list = list.stream().sorted(Comparator.comparing(v -> {
            return v.getSystemFlag() ? 0 : 1;
        })).toList();
        for (ProcessCompDTO processCompDTO : list) {
            String groupCode = processCompDTO.getGroupCode();
            if (StrUtil.isBlank(groupCode)) {
                continue;
            }

            Tree<String> stringTree = treeHasByCode(groupCode, tree);
            if (ObjectUtil.isNotNull(stringTree)) {
                continue;
            }
            stringTree = treeHasByCode(SquareLakeGroupBizServiceImpl.ALL_GROUP_CODE, tree);
            if (ObjectUtil.isNull(stringTree)) {
                continue;
            }
            Tree<String> tc = new Tree<>();
            tc.setId(IdUtil.getSnowflakeNextIdStr());
            tc.setName(processCompDTO.getCompName());
            tc.setParentId(stringTree.getId());
            tc.put("groupCode", groupCode);
            stringTree.addChildren(tc);

        }


        return tree;
    }


    private Tree<String> treeHasByCode(String groupCode, List<Tree<String>> tree) {
        if (CollUtil.isEmpty(tree)) {
            return null;
        }
        Tree<String> result = null;
        for (Tree<String> st : tree) {

            String str = MapUtil.getStr(st, "groupCode");
            if (StrUtil.equals(str, groupCode)) {
                result = st;
                break;
            }
            List<Tree<String>> children = st.getChildren();
            Tree<String> stringTree = treeHasByCode(groupCode, children);
            if (ObjectUtil.isNotNull(stringTree)) {
                result = stringTree;
                break;
            }
        }
        return result;
    }
}
